package com.example.fengyungo.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.fengyungo.domain.pojo.Message;
import com.example.fengyungo.service.MessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * WebSocket服务
 */
@Component
@ServerEndpoint("/ws/{sid}")
@Slf4j
public class WebSocketServer {

    //  这里使用静态，让 service 属于类
    private static MessageService messageService;
    private static RedisTemplate redisTemplate;
    /**
     * 消息id
     */
    String messageId;
    /**
     * 发送方id
     */
    String senderId;
    /**
     * 接收方id
     */
    String receiverId;
    /**
     * 消息内容
     */
    String content;
    /**
     * 发送时间
     */
    String sendTime;
    /**
     * 用户id
     */
    String userId;
    /**
     * 司机id
     */
    String driverId;

    // 注入的时候，给类的 service 注入
    @Autowired
    public void setChatService(MessageService messageService, RedisTemplate redisTemplate) {
        WebSocketServer.messageService = messageService;
        WebSocketServer.redisTemplate = redisTemplate;
    }

    /**
     * 清理缓存数据
     *
     * @param pattern String
     */
    private void cleanCache(String pattern) {
        Set keys = redisTemplate.keys(pattern);
        redisTemplate.delete(keys);
    }

    // 存放会话对象
    private static ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        log.info("客户端：" + sid + "建立连接");
        sessionMap.put(sid, session);
        log.info("sessionMap:" + sessionMap);
//        sendToClient(sid, "连接成功-from server");
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, @PathParam("sid") String sid) {
        // log.info("收到来自客户端：" + sid + "的信息:" + message);
        if (message.equals("ping")) {
            sendToClient(sid, "pong");
        } else {
            // 将message转为json数据
            JSONObject jsonObject;
            try {
                jsonObject = JSON.parseObject(message);
                messageId = jsonObject.getString("messageId");
                senderId = jsonObject.getString("senderId");
                receiverId = jsonObject.getString("receiverId");
                content = jsonObject.getString("content");
                sendTime = jsonObject.getString("sendTime");
                sendToClient(receiverId, message);
                // 清除缓存
                cleanCache("fengyungomessage*");
                // 将消息存入数据库中
                Message newMessage = new Message(messageId, senderId, receiverId, content, sendTime);
                // log.info("newMessage:" + newMessage);
                messageService.insertMessage(newMessage);
                // 修改司机消息列表的内容和时间
                messageService.updateDriverLastContentAndTime(newMessage);
                // 修改用户消息列表的内容和时间
                messageService.updateUserLastContentAndTime(newMessage);
                // 判断发送方和接收方用户的身份
                // 发送方为用户，接收方为司机
                if (senderId.charAt(0) == 'u') {
                    userId = senderId;
                    driverId = receiverId;
                    // TODO: 2023/12/29 如果消息列表中不存在则增加到用户、司机消息列表中

                    // TODO: 2023/12/29 消息列表中被删除的重新添加到消息列表中（修改状态）

                    // 修改司机的未读数
                    Integer driverUnread = messageService.getDriverUnread(driverId, userId);
                    log.info("driverUnread:" + driverUnread);
                    messageService.updateDriverUnread(driverId, userId, driverUnread + 1);
                } else {
                    // 发送方为司机，接收方为用户
                    userId = receiverId;
                    driverId = senderId;
                    // TODO: 2023/12/29 如果消息列表中不存在则增加到用户、司机消息列表中

                    // TODO: 2023/12/29 消息列表中被删除的重新添加到消息列表中（修改状态）

                    // 修改用户的未读数
                    Integer userUnread = messageService.getUserUnread(driverId, userId);
                    messageService.updateUserUnread(driverId, userId, userUnread + 1);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 连接关闭调用的方法
     *
     * @param sid 用户的id
     */
    @OnClose
    public void onClose(@PathParam("sid") String sid) {
        log.info("连接断开:" + sid);
        sessionMap.remove(sid);
    }

    /**
     * 发生错误时调用
     *
     * @param session Session
     * @param t       异常
     */
    @OnError
    public void onError(Session session, Throwable t) {
        log.error("WebSocket连接发生异常，message:" + t.getMessage());
    }

    /**
     * 群发
     *
     * @param message 消息
     */
    public void sendToAllClient(String message) {
        Collection<Session> sessions = sessionMap.values();
        log.info("sessions:" + sessions);
        for (Session session : sessions) {
            try {
                // 服务器向客户端发送消息
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 向指定的客户端发送消息
     *
     * @param message 消息
     * @param sid     指定客户端的sid
     */
    public void sendToClient(String sid, String message) {
        Session session = sessionMap.get(sid);
        log.info("sid:" + sid + ",session:" + session);
        if (session != null) {
            try {
                // 服务器向指定客户端发送消息
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}